﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;
using StockTrader.API.TradingAlgos;
using StockTrader.Broker.IciciDirect;
using StockTrader.Common;
using StockTrader.Core;
using StockTrader.Platform.Logging;
using StockTrader.Stocks.Utilities.Broker;
using StockTrader.Utilities;
using StockTrader.Utilities.Broker;

namespace StockTrader.UI.Trader
{
    public partial class STRunner
    {
        public STRunner(string login, string pass)
        {
            _login = login;
            _pass = pass;
        }
        

        //StockChart _chart = new StockChart();
        string _loginId;
        IciciDirectBroker _iciciDirectAccount;
        List<BrokerAccountThread> _brokerThreads = new List<BrokerAccountThread>();
        List<GenericLifeThread> _generalThreads = new List<GenericLifeThread>();
        List<StockThread> _stockThreads = new List<StockThread>();
        public AddTickChartDelegate _getChartDataDelegate;
        BrokerAccountThread _iciciLoginThread = new BrokerAccountThread();
        bool bContinueRemoteTh = true;
        bool bContinueMktCloseChkrTh = true;

        string _login;
        string _pass;

        // Core method

        private void loginSubmit_Click(object sender, EventArgs e)
        {
            FileTracing.TraceOut("Testing...");
            BrokerErrorCode errorCode = BrokerErrorCode.Success;
            // Create ICICI broker account
            _iciciDirectAccount = new IciciDirectBroker(this.loginIdTb.Text, this.passwordTb.Text);

            errorCode = TryLoggingIn();

            if (errorCode == BrokerErrorCode.Success)
            {
                SetPanelsOnLogin();

                this.welcomeMsg.Text = "Welcome " + _loginId + " !";

                StartAllThreads();
            }
        }

        private void StartAllThreads()
        {
            // Thread 1
            StartLoginCheckerThread();

            // Start MArket closing checker 2
            //var thMktClosingChkr= new Thread(() =>
            //{
            //    CheckMarketClosing();
            //});
            //thMktClosingChkr.Start();
            var obj = new GenericLifeThread { thread = new Thread(new ParameterizedThreadStart(CheckMarketClosing)) };
            obj.thread.Start(obj);
            _generalThreads.Add(obj);

            // Start Remote Command checker 3
            //var thRemoteChkr = new Thread(() =>
            //{
            //    CheckRemoteCommand();
            //});
            //thRemoteChkr.Start();
            obj = new GenericLifeThread { thread = new Thread(new ParameterizedThreadStart(CheckRemoteCommand)) };
            obj.thread.Start(obj);
            _generalThreads.Add(obj);

            // Start Algos
            double perc = 1.25;
            InstrumentType instr = InstrumentType.FutureStock;
            StartAlgoThread("DLFLIM", 1000, perc, instr); Thread.Sleep(1000 * 5);
            StartAlgoThread("EDUSOL", 1000, perc, instr); Thread.Sleep(1000 * 5);
            StartAlgoThread("UTIBAN", 250, perc, instr); Thread.Sleep(1000 * 5);
            StartAlgoThread("YESBAN", 1000, perc, instr); Thread.Sleep(1000 * 5);
            StartAlgoThread("INDREL", 4000, perc, instr); Thread.Sleep(1000 * 5);
            StartAlgoThread("SAIL", 2000, perc, instr); Thread.Sleep(1000 * 5);
            StartAlgoThread("RELCOM", 4000, perc, instr); Thread.Sleep(1000 * 5);

            StartAlgoThread("MINIFT", 20, 0.25, InstrumentType.FutureIndex); Thread.Sleep(1000 * 5);
            StartAlgoThread("MINIFT", 20, 0.5, InstrumentType.FutureIndex); Thread.Sleep(1000 * 5);
            StartAlgoThread("MINIFT", 20, 1.25, InstrumentType.FutureIndex); Thread.Sleep(1000 * 5);
        }

        private void StartLoginCheckerThread()
        {
            BrokerErrorCode errorCode = BrokerErrorCode.Success;
            errorCode = _iciciDirectAccount.CheckAndLogInIfNeeded(false);
       
            // If login password is invalid then immediately exit the program 
            // to avoid locking of account by retrying with bad login/password
            if (errorCode == BrokerErrorCode.InvalidLoginPassword || errorCode == BrokerErrorCode.ChangePassword)
            {
                FileTracing.TraceOut("InvalidLoginPassword");
                return;
            }
            if (errorCode != BrokerErrorCode.Success)
            {
                throw new Exception("CheckAndLogInIfNeeded(). BrokerErrorCode=" + errorCode.ToString());
            }

            // Separate Login thread in background
            Thread thread = new Thread(new ParameterizedThreadStart(LoginUtils.Background_LoginCheckerThread));
            BrokerAccountObject iciciAccObj = new BrokerAccountObject(_iciciDirectAccount);
            _iciciLoginThread.brokerAccountObj = iciciAccObj;
            _iciciLoginThread.thread = thread;

            //_brokerThreads.Add(_iciciLoginThread);

            _iciciLoginThread.thread.Name = "Main Login Thread of \"" + _loginId + "\"";
            _iciciLoginThread.thread.IsBackground = true;

            _iciciLoginThread.thread.Start(iciciAccObj);
        }
        private TradingAlgo GetAlgo(string stockCode, int qty, double perc, InstrumentType instr)
        {
            // Set Algo Params
            AlgoParams algoParams = new AlgoParams();
            algoParams.R1 = "2012";
            algoParams.R2 = "IEOD-1min-mock";
            algoParams.DataDelegate = null;
            algoParams.ChartDelegate = null;
            algoParams.IsMock = true;
            algoParams.IsReplayMode = false;
            algoParams.ReplayTickFile = @"D:\StockData\NIFTY-5Oct2005-7Apr2006-10000ticks.txt";
            algoParams.PositionsFile = @"D:\StockData\NIFTY_positions1.txt";
            algoParams.AlgoId = 1;
            algoParams.UseProbableTradeValue = false;
            algoParams.IsMarketClosingSquareOff = true;
            //Params.isSquareOffTrigger = false;
            //Params.isMinProfitMust = false;
            algoParams.PercMarketDirectionChange = perc;
            //Params.percSquareOffThreshold = 0;
            //Params.percStoploss = 0;
            //Params.percMinProfit = 0;
            //Params.allowShort = true;
            //Params.allowLong = true;
            //Params.startOrders = null;
            algoParams.Broker = _iciciDirectAccount;
            algoParams.StockCode = stockCode;
            algoParams.Quantity = qty;
            algoParams.InstrumentType = instr;
            algoParams.ExpiryDate = MarketUtils.GetExpiryExactDate(new DateTime(2012, 4, 26));
            algoParams.MaxTotalPositions = 1;
            algoParams.MaxLongPositions = 1;
            algoParams.MaxShortPositions = 1;
            algoParams.LongCeilingPrice = 100000;
            algoParams.ShortFloorPrice = 0.01;
            algoParams.PercPositionSpacing = 0.01;
            algoParams.PercBrokerage = 0.05;
            algoParams.MarginFraction = 0.25;

            TradingAlgo algo = new AlgoMinMax(algoParams);

            return algo;
        }
        private void StartAlgoThread(string stockCode, int qty, double perc, InstrumentType instr)
        {
            ITradingAlgo algo = GetAlgo(stockCode, qty, perc, instr);

            StockAndBrokerObject stockTraderObj = new StockAndBrokerObject(_iciciDirectAccount, null, algo);
            Thread thread = new Thread(new ParameterizedThreadStart(AlgoRunner.Background_StockWorkerThread));

            StockThread stockAlgoThread = new StockThread();
         
            stockAlgoThread.stockAndBrokerObj = stockTraderObj;
            stockAlgoThread.thread = thread;

            _stockThreads.Add(stockAlgoThread);

            stockAlgoThread.thread.Name = "\"" + _loginId + "\": " + stockCode;
            stockAlgoThread.thread.IsBackground = true;

            stockAlgoThread.thread.Start(stockTraderObj);
        }


        private void CheckMarketClosing(object obj)
        {
            var thObj = (GenericLifeThread)obj;
            while (!thObj.bStopThread)//bContinueMktCloseChkrTh)
            {
                bool IsMarketOpen = MarketUtils.IsMarketOpen();

                if (!IsMarketOpen)
                    break;

                else
                    Thread.Sleep(1000 * 60 * 2);
            }

            logoutBtn_Click(null, null);

            // Hibernate system
            //bool retVal = Application.SetSuspendState(PowerState.Hibernate, true, false); 
        }

        private void CheckRemoteCommand(object obj)
        {
            var thObj = (GenericLifeThread)obj;
            while (!thObj.bStopThread)//bContinueRemoteTh)
            {
                ProgramRemoteControl val = RemoteUtils.GetProgramRemoteControlValue();

                if (val.Equals(ProgramRemoteControl.STOP) ||
                            val.Equals(ProgramRemoteControl.HIBERNATE))
                {
                    FileTracing.TraceOut("AlgoRunner: Remote Control issued STOP/HIBERNATE command to the Algo\n");
                    break;
                }

                else
                    Thread.Sleep(1000 * 60 * 4);
            }
        }

        private BrokerErrorCode TryLoggingIn()
        {
            // LOGIN 
            BrokerErrorCode errorCode = BrokerErrorCode.Success;
            errorCode = _iciciDirectAccount.CheckAndLogInIfNeeded(true, false);
            // If login password is invalid then immediately exit the program 
            // to avoid locking of account by retrying with bad login/password

            string message = "";

            switch (errorCode)
            {
                case BrokerErrorCode.ChangePassword:
                    message = "You need to change password. Goto website and change before logging in here.";
                    break;

                case BrokerErrorCode.InvalidLoginPassword:
                    message = "Invalid LoginIdPassword. Please try, but not more than 2 times to avoid locking the account.";
                    break;

                case BrokerErrorCode.Success:
                    message = "Login Successful";
                    break;

                default:
                    message = errorCode.ToString();
                    break;
            }

            FileTracing.TraceOut("Login for " + _login + "." + message);

            return errorCode;
        }
        private void EndStockThreads()
        {
            foreach (StockThread stockThread in _stockThreads)
            {
                // signal the stock threads to stop and wait for them to complete
                stockThread.stockAndBrokerObj.bStopThread = true;
            }

            foreach (StockThread stockThread in _stockThreads)
            {
                stockThread.thread.Join();
            }
            _stockThreads.Clear();

            for (int i = 0; i < _generalThreads.Count; i++)
            {
                // signal the generic threads to stop and wait for them to complete
                _generalThreads[i].bStopThread = true;
                _generalThreads[i].thread.Join();
            }
            _generalThreads.Clear();

            _iciciLoginThread.brokerAccountObj.bStopThread = true;
            _iciciLoginThread.thread.Join();

        }
        private void logoutBtn_Click(object sender, EventArgs e)
        {
            EndStockThreads();

            _iciciDirectAccount.LogOut();

            string logOutMessage = _loginId + " has been successfully logged out";

            FileTracing.TraceOut(logOutMessage);
        }
    }
}
